/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */

#include "BlenderMaterialLoader.h"

#include "BlenderTextureLoader.h"

#include "OgreTechnique.h"
#include "OgreTextureUnitState.h"
#include "OgreTextureManager.h"

#include "BlenderDefine.h"
#include "GUtil.h"

namespace GNgine
{
	
	BlenderMaterialLoader::BlenderMaterialLoader(Ogre::String group,bParse::bBlenderFile* blenderFile)
		: _group(group), _bFile(blenderFile),_bImageLookup()
	{
	}

	BlenderMaterialLoader::~BlenderMaterialLoader()
	{
		
	}

	void BlenderMaterialLoader::getOgreMaterialFromMaterial(Ogre::MaterialPtr ptr, Blender::Material *matr, Blender::Mesh *me, int flags)
	{
	}

	void BlenderMaterialLoader::setOgreMaterialDefault(Ogre::MaterialPtr ptr, bool lighting, int flags, int alpha)
	{
		if(ptr.isNull()){
			return;
		}
		_material=ptr.getPointer();
		_tech=_material->getTechnique(0);
		
		ptr->setLightingEnabled(lighting&&hasLamp());
		ptr->setDiffuse(0.8, 0.8, 0.8, 1.0);
		applyTexFace(flags,alpha);
	}

	void BlenderMaterialLoader::addTextureUnit(Ogre::MaterialPtr materialPtr, Blender::Image *bImage, int layerIndex)
	{
		Ogre::Pass* pass=materialPtr->getTechnique(0)->getPass(0);
		addTextureUnit(pass, bImage,layerIndex);
	}

	void BlenderMaterialLoader::handleMultiPass(void)
	{
	}

	void BlenderMaterialLoader::handleStd(void)
	{
	}

	void BlenderMaterialLoader::applyAmbientPass(void)
	{
	}

	void BlenderMaterialLoader::applyLightPass(void)
	{
	}

	void BlenderMaterialLoader::applyTexturePass(void)
	{
	}

	bool BlenderMaterialLoader::applyTexFace(int flags, int alpha)
	{
		if(!_material||!_tech){
			return false;
		}

		if(flags& TF_INVISIBLE){
			_material->setReceiveShadows(false);
			_tech->setColourWriteEnabled(false);
			_tech->setDepthWriteEnabled(false);
			_tech->setLightingEnabled(false);
			return false;
		}

		if (flags & TF_LIGHT){
			_tech->setLightingEnabled(hasLamp());
		}

		if (flags &TF_TWOSIDE){
			_tech->setCullingMode(Ogre::CULL_NONE);
			_tech->setManualCullingMode(Ogre::MANUAL_CULL_NONE);
		}

		if(flags& TF_ALPHA){
			_tech->getPass(0)->setAlphaRejectSettings(Ogre::CMPF_GREATER_EQUAL,128);
			_tech->setSceneBlending(Ogre::SBF_SOURCE_ALPHA,Ogre::SBF_ONE_MINUS_SOURCE_ALPHA);
		}

		if(alpha&TF_ADD){
			_tech->setSceneBlending(Ogre::SBF_ONE, Ogre::SBF_ONE);
		}
		return true;
	}

	bool BlenderMaterialLoader::hasLamp(void)
	{
		assert(_bFile);
		bParse::bMain *bMainPtr=_bFile->getMain();
		return bMainPtr->getLamp()->size()!=0;
	}

	Ogre::Pass *getOrCreatePass(size_t idx)
	{
		Ogre::Pass* pass=0;
		return pass;
	}

	int BlenderMaterialLoader::getNumTextures(void)
	{
		return 0;
	}

	Blender::MTex* BlenderMaterialLoader::getTexture(size_t i)
	{
		Blender::MTex* bTex=0;
		return bTex;
	}
	Blender::MTex* BlenderMaterialLoader::getTexture(int mapto, int fallback)
	{
		Blender::MTex* bTex=0;
		return bTex;
	}

	MTexList BlenderMaterialLoader::getTextures(int mapto)
	{
		MTexList list;
		return list;
	}

	int BlenderMaterialLoader::getUVLayer(Blender::MTex *te)
	{
		return 0;
	}

	Ogre::String BlenderMaterialLoader::getSpecularDef(void)
	{
		return "";
	}
	Ogre::String BlenderMaterialLoader::getDiffuseDef(void)
	{
		return "";
	}

	Ogre::TextureUnitState* BlenderMaterialLoader::addTextureUnit(Ogre::Pass* ptr, Blender::MTex *tex)
	{
		Ogre::TextureUnitState* texState=0;
		return texState;
	}

	void BlenderMaterialLoader::addBlenderImage(Blender::Image* bImage)
	{
		assert(bImage);
		ImageTextureMap::iterator it= _bImageLookup.find(bImage);
		if(it!=_bImageLookup.end()){
			return;
		}

		GPath p(bImage->name);
		Ogre::String base=p.base();
		if(GUtil::isResource(base)){
			Ogre::TextureManager::getSingleton().create(base,_group);
			return;
		}

		BlenderTextureLoader *loader=new BlenderTextureLoader(bImage);
		//when to delete loader?BUG: cause memory leak

		Ogre::TexturePtr tex= Ogre::TextureManager::getSingleton().create(BLENDER_IDNAME(bImage), _group, true, loader);
		if (!tex.isNull()){
			_textures.push_back(tex.getPointer());
			_bImageLookup.insert(ImageTextureMap::value_type(bImage,tex.getPointer()));
		}
	}

	Ogre::TextureUnitState* BlenderMaterialLoader::addTextureUnit(Ogre::Pass* pass, Blender::Image *bImge, int layerIndex)
	{
		Ogre::TextureUnitState *state= 0;
		/// can only use packed file or file path,ImBuf is internal to blender
		GPath p(bImge->name);
		const Ogre::String& base=p.base();
		if(!bImge&&!bImge->packedfile&&!GUtil::isResource(base)){
			return 0;
		}

		addBlenderImage(bImge);

		if(GUtil::isResource(base)){
			state=pass->createTextureUnitState(base);
		}else{
			state=pass->createTextureUnitState(BLENDER_IDNAME(bImge));
		}
		if(state&&layerIndex>=0&&layerIndex<=7){
			state->setTextureCoordSet(layerIndex);
		}

		if(state){
			Ogre::TextureUnitState::TextureAddressingMode u,v,w;

			u=bImge->tpageflag & IMA_CLAMP_U ? Ogre::TextureUnitState::TAM_CLAMP : Ogre::TextureUnitState::TAM_WRAP;
			v=bImge->tpageflag & IMA_CLAMP_V ? Ogre::TextureUnitState::TAM_CLAMP : Ogre::TextureUnitState::TAM_WRAP;
			w=Ogre::TextureUnitState::TAM_WRAP;
			state->setTextureAddressingMode(u,v,w);
		}

		return state;
	}

	void BlenderMaterialLoader::applyParameters(Ogre::GpuProgramParametersSharedPtr params)
	{
	}
}
